#ifndef XGE_XLAZY_INSTANCE_H_
#define XGE_XLAZY_INSTANCE_H_
#include "xge_common_config.h"
#include "xsync.h"
#include "xatomic_operation.h"
#include "xassert.h"
#include "xatexit_manager.h"
#include "xthread.h"

namespace xge{
namespace xge_internal{
  // The LazyInstance is a funny stuff  
  // since it is totally POD type when it has been designed 
  // and the X type will ONLY be initialized when it is first accessed
  // and it is totally thread safe class.
  // We use a preallocated trick to do the memory management
  // which is safe as we think at least
  // A instance here has its original status like
  // Not created , creating , created

  // TypeTrait : 
  // concept:
  // 1. Destroy( X * ptr ) ; destroy the memory of this pointer
  // 2. Construct( void* memory ) ; Call the placement new ( anything you wish ) on th memory
  // this piece of memory is fixed bounded to sizeof(X) return the X* ptr
  // 3. kDestroy indicate needs destroy the pointer or not
  // 4. kDestroyPriority  needs the priority of this destroy function register on the XAtExitManager

  template < typename X , typename TypeTrait > class LazyInstance {
  public:
    enum {
      NOT_CREATED = 0,
      CREATING    = 1,
      CREATED     = 2
    };
    // This function is safe to use as it will simply return the Instance(X)'s pointer
    // and it will use lazy initialization mechanism , namely when the first time you
    // call this function the X will be initialized and it is thread safe as well 
    X* GetInstancePtr(); 
    X& GetInstance(){
      return *GetInstancePtr();
    }
  private:
    // needs instance will create the instance
    bool NeedsInstance();
    // complete the instance creating 
    // which means register the deletor in the XAtExitManager
    void CompleteInstance();
    // static deletor 
    // this is used to register into the XAtExitManager
    static bool DeleteThisInstance( void* lazy_instance ) {
      LazyInstance<X,TypeTrait> * lazy_ptr = static_cast< LazyInstance<X,TypeTrait> * >(lazy_instance);
      // You may call the destructor of this pointer as you wish
      TypeTrait::Destroy( lazy_ptr->instance_ );
      lazy_ptr->instance_ = NULL;
      StoreAndRelease(lazy_ptr->status_,(AtomicOperation::Atomic_t)NOT_CREATED);
      return true;
    }

  private:
    typedef unsigned char byte_t;
    // the memory which will be used to initialized the stuff here
    byte_t memory_[sizeof(X)];
    // the status of this instance  
    // this atomic_t operation will not be called 
    // which means I do not initialized this status
    // we do not have to set this status_ to zero
    // it will randomly set a value or set to zero ( If you declare it as static stuff )
    // if it is not status_ we treat it as zero
    // if it is the zero , ok , we hit it.
    AtomicOperation::Atomic_t status_;
    // the instance itself
    X* instance_;
  };

  template < typename X , typename TypeTrait >
  X* LazyInstance<X,TypeTrait>::GetInstancePtr() {
    // check if we reach here the status_ 
    // If it is created ! we acquire this information only 
    // by checking the status_ once , a simply LOCK asm operation
    // if not :
    // Ok it may be On CREATING or totally NOT_CREATED
    if( ( AcquireAndLoad(status_) != CREATED ) && NeedsInstance() ) { 
      instance_ = TypeTrait::Construct((void*)(memory_)) ;
      // complete the whole creating process now
      CompleteInstance();
    }

    return instance_;
  }

  template< typename X , typename TypeTrait > 
  bool LazyInstance<X,TypeTrait>::NeedsInstance() {
    if( AtomicOperation::AtomicCAS((AtomicOperation::OperationTypePtr)(&status_), CREATING , NOT_CREATED ) == NOT_CREATED ) {
      return true;
    } 
    // The object is creating we just wait until it is created 
    // This spin-lock is not that kind of good , in fact 
    // it do not have spin operation , just yield ....
    // it may change 
    while( LoadAndAcquire(status_) != CREATED ) 
      ThreadManager::SwithToAnotherThread();
    // reach here is ok now
    return false;
  }

  template< typename X , typename TypeTrait >
  void LazyInstance<X,TypeTrait>::CompleteInstance() {
    // Complete the whole instance stuff here
    if( TypeTrait::kDestroy ) {
      AtExitManager::RegisterProxy( 
        DeleteThisInstance , 
        this , 
        TypeTrait::kDestroyPriority,
        TypeTrait::kDeleteErrorString
        );
    }
    // A Release And Store is ok
    ReleaseAndStore(status_,(AtomicOperation::Atomic_t)CREATED);
  }

} // namespace xge_internal
}// namespace xge


#endif// XGE_XLAZY_INSTANCE_H_